package com.example.datasource;

import com.alibaba.druid.pool.DruidDataSource;
import com.example.holder.TenantHolder;
import com.example.pojo.Tenant;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author wangy
 * @create 2021/7/12 17:18
 * @Description 集成AbstractRoutingDataSource实现动态数据源
 */
@Component
public class DynamicDataSource extends AbstractRoutingDataSource {

    //默认数据源
    private static DataSource defaultDataSource;
    //保存所有的数据源
    private static Map<Object,Object> targetDataSources = new HashMap<>();

    static {
        //初始化默认数据源
        DruidDataSource source = new DruidDataSource();
        source.setUrl("jdbc:mysql://localhost/defaultDB?useUnicode=true&characterEncoding=UTF-8");
        source.setUsername("root");
        source.setPassword("123456");
        source.setDriverClassName("com.mysql.cj.jdbc.Driver");
        source.setInitialSize(2);
        source.setMinIdle(2);
        source.setMaxActive(5);
        defaultDataSource = source;
    }

    /**
     * 获取数据库连接
     * @return
     * @throws SQLException
     */
    @Override
    public Connection getConnection() throws SQLException {
        return super.getConnection();
    }

    /**
     * 设置默认数据源
     * @param defaultTargetDataSource 存储所有租户数据源信息的数据源
     */
    @Override
    public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
        super.setDefaultTargetDataSource(defaultDataSource);
    }

    @Override
    public void afterPropertiesSet() {
        //初始化所有租户的数据源
        initTargetDataSources();
        //一些参数设置操作
        super.afterPropertiesSet();
    }

    /**
     * 初始化所有租户的数据源
     */
    public void initTargetDataSources(){
        //得到所有动态数据源
        JdbcTemplate jdbcTemplate = new JdbcTemplate(defaultDataSource);
        List<Map<String, Object>> list =
                jdbcTemplate.queryForList("select tenant_name, tenant_code, db_url, db_user, db_password, tenant_introduce from t_tenant;");

        Tenant tenant = null;
        for (Map<String, Object> map : list) {
            tenant = new Tenant();
            tenant.setTenantName((String) map.get("tenant_name"));
            tenant.setTenantCode((String) map.get("tenant_code"));
            tenant.setDbUrl((String) map.get("db_url"));
            tenant.setDbUser((String) map.get("db_user"));
            tenant.setDbPassword((String) map.get("db_password"));
            tenant.setTenantIntroduce((String) map.get("tenant_introduce"));
            //创建租户的数据源
            DataSource tenantDataSource = createDataSourceByTTenant(tenant);
            //放到容器中
            targetDataSources.put(tenant.getTenantCode(), tenantDataSource);
        }
        //设置所有的数据源Map
        super.setTargetDataSources(targetDataSources);
    }

    /**
     * 每次sql请求会获取使用哪个数据源对应的key
     * @return
     */
    @Override
    protected Object determineCurrentLookupKey() {
        return TenantHolder.getTenantCode();
    }

    /**
     * 每次sql请求会决定使用哪个数据源
     * @return
     */
    @Override
    protected DataSource determineTargetDataSource() {

        DataSource dataSource = null;
        //如果未获取到
        if (null == determineCurrentLookupKey()) {
            dataSource =  defaultDataSource;
        }else {
            dataSource = (DataSource) targetDataSources.get(determineCurrentLookupKey());
        }
        return dataSource;
    }

    /**
     * 根据表里数据源 初始化话数据源
     * @param tenant
     * @return
     */
    public DataSource createDataSourceByTTenant(Tenant tenant){
        DruidDataSource source = new DruidDataSource();
        source.setUrl(tenant.getDbUrl());
        source.setUsername(tenant.getDbUser());
        source.setPassword(tenant.getDbPassword());
        source.setDriverClassName("com.mysql.cj.jdbc.Driver");
        source.setInitialSize(2);
        source.setMinIdle(1);
        source.setMaxActive(3);
        return source;
    }

}
